using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using Microsoft.Web.WebView2.Core;
using log4net;
using System.Reflection;
using System.Globalization;
using System.IO;
using System.Net;

namespace Comteck.Winforms.Controls {
  public partial class UcUEditor : UcBase {

    //private bool NotFirst { get; set; }
    //private bool IsLoaded { get; set; }

    private static readonly ILog Logger = LogManager.GetLogger(typeof(UcUEditor));

    /// <summary>
    /// 内容
    /// </summary>
    private string Content { get; set; }


    public UcUEditor() {
      InitializeComponent();
      _ = InitializeWebBrowerAsync();
    }

    private static CoreWebView2Environment env;

    private async Task InitializeWebBrowerAsync() {
      if(env == null) {
        env = await CoreWebView2Environment.CreateAsync(null,
          options: new CoreWebView2EnvironmentOptions("--disable-web-security --allow-file-access-from-files"));
      }
      await ViewUEditor.EnsureCoreWebView2Async(env);
#if !DEBUG
      ViewUEditor.CoreWebView2.Settings.AreDevToolsEnabled = false;
      ViewUEditor.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
#endif
      ViewUEditor.CoreWebView2.AddWebResourceRequestedFilter($"{SysGlobal.Settings.GatewayUrl}/*", CoreWebView2WebResourceContext.All);
      ViewUEditor.CoreWebView2.WebResourceRequested += this.OnWebRequested;
    }

    private void OnWebRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e) {
      if (e.Request.Headers.Contains("Authorization"))
        return;
      if (string.IsNullOrEmpty(SysGlobal.IdentityResponse.Access_Token))
        return;
      e.Request.Headers.SetHeader("Authorization", $"Bearer {SysGlobal.IdentityResponse.Access_Token}");
    }

    public async Task SetUEditorInnertText(string content) {
      content = content ?? string.Empty;
      content = content.Trim('\"', '\'');
      content = content.Replace("\r\n", "\n");
      content = content.Replace("\n", "\\n");
      await ViewUEditor.CoreWebView2
        .ExecuteScriptAsync($"document.getElementById('ueditor_0').contentWindow.document.querySelector('.view .view').innerText='{content}'");
    }

    public async Task<string> GetUEditorInnertText() {
      string content = await ViewUEditor.CoreWebView2
          .ExecuteScriptAsync($"document.getElementById('ueditor_0').contentWindow.document.querySelector('.view .view').innerText");
      if (content.Length > 2 && content[0] == '\"' && content[content.Length - 1] == '\"') {
        content = content.Substring(1, content.Length - 2);
      }
      return content;
    }

    public async Task SetUEditorInnertHTML(string content) {
      content = content ?? string.Empty;
      content = Encode(content);
      await ViewUEditor.CoreWebView2
          .ExecuteScriptAsync($"document.getElementById('ueditor_0').contentWindow.document.querySelector('.view .view').innerHTML='{content}'");
    }

    public async Task<string> GetUEditorInnertHTML() {
      string content = await ViewUEditor.CoreWebView2
          .ExecuteScriptAsync($"document.getElementById('ueditor_0').contentWindow.document.querySelector('.view .view').innerHTML");
      content = UnescapeUnicode(content);
      if (content.Length > 2 && content[0] == '\"' && content[content.Length - 1] == '\"') {
        content = content.Substring(1, content.Length - 2);
      }
      return content;
    }
    private static void AppendCharAsUnicodeJavaScript(StringBuilder builder, char c) {
      builder.Append("\\u");
      builder.Append(((int)c).ToString("x4", CultureInfo.InvariantCulture));
    }

    private static bool CharRequiresJavaScriptEncoding(char c) {
      return c < 0x20 // control chars always have to be encoded
             || c == '\"' // chars which must be encoded per JSON spec
             || c == '\\'
             || c == '\'' // HTML-sensitive chars encoded for safety
             || c == '<'
             || c == '>'
             || c == '&' // Bug Dev11 #133237. Encode '&' to provide additional security for people who incorrectly call the encoding methods (unless turned off by backcompat switch)
             || c == '\u0085' // newline chars (see Unicode 6.2, Table 5-1 [http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf]) have to be encoded (DevDiv #663531)
             || c == '\u2028'
             || c == '\u2029';
    }
    public static string Encode(string value) {
      if (string.IsNullOrEmpty(value))
        return string.Empty;
      int startIndex = 0;
      int count = 0;

      StringBuilder sb = null;
      for (int i = 0; i < value.Length; i++) {
        char c = value[i];

        if (CharRequiresJavaScriptEncoding(c)) {
          if (sb == null) {
            sb = new StringBuilder(value.Length + 5);
          }
          if (count > 0) {
            sb.Append(value, startIndex, count);
          }
          startIndex = i + 1;
          count = 0;
        }


        switch (c) {
          case '\r':
            sb.Append("\\r");
            break;
          case '\t':
            sb.Append("\\t");
            break;
          case '\"':
            sb.Append("\\\"");
            break;
          case '\\':
            sb.Append("\\\\");
            break;
          case '\n':
            sb.Append("\\n");
            break;
          case '\b':
            sb.Append("\\b");
            break;
          case '\f':
            sb.Append("\\f");
            break;
          default:
            if (CharRequiresJavaScriptEncoding(c)) {
              AppendCharAsUnicodeJavaScript(sb, c);
            } else {
              count++;
            }
            break;
        }
      }

      if (sb == null)
        return value;
      if (count > 0)
        sb.Append(value, startIndex, count);
      return sb.ToString();
    }

    public string UnescapeUnicode(string str) // 将unicode转义序列(\uxxxx)解码为字符串
    {
      return (System.Text.RegularExpressions.Regex.Unescape(str));
    }

    public void LoadUcUEditor(string content, string url = null) {
      if (string.IsNullOrEmpty(url))
        url = $"{SysGlobal.HttpClient.BaseAddress}{SysGlobal.Settings.AppName_MultiChannel}/api/UEditor/index";

      var requestUrl = $"{SysGlobal.HttpClient.BaseAddress}{SysGlobal.Settings.AppName_MultiChannel}/api/UEditor";
      this.Content = content;
      ViewUEditor.Source = new Uri($"file:///{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "webview", "ueditor.html")}?requestPath={WebUtility.UrlEncode(requestUrl)}");
      //ViewUEditor.Source = new Uri($"{url}?Upload_Token={SysGlobal.IdentityResponse.Access_Token}");
      //this.IsLoaded = true;
    }

    // Clears autofill data.
    private async Task ClearAutofillData() {
      // 此功能无效，无效做清空的动作

      CoreWebView2Profile profile;
      if (ViewUEditor.CoreWebView2 != null) {
        profile = ViewUEditor.CoreWebView2.Profile;
        // Get the current time, the time in which the browsing data will be cleared
        // until.
        //System.DateTime endTime = DateTime.Now;
        //System.DateTime startTime = DateTime.Now.AddHours(-1);
        // Offset the current time by one hour to clear the browsing data from the
        // last hour.
        //CoreWebView2BrowsingDataKinds dataKinds = CoreWebView2BrowsingDataKinds.FileSystems | CoreWebView2BrowsingDataKinds.CacheStorage;
        await profile.ClearBrowsingDataAsync();

        Logger.Info("ClearBrowsingDataAsync");
      }
    }

    private async void ViewUEditor_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) {
      if (this.Content != null) {
        await this.SetUEditorInnertHTML(this.Content);

        await this.ClearAutofillData();
      }
    }

  }
}
